package de.szut.pongsim.physics;

public class Board {

	private static final int HEIGHT = 60;
	private static final int WIDTH = 65;
	private static final int UPPER_BOUND = HEIGHT - 1;
	private static final int LOWER_BOUND = 0;
	private static final int PAD_HEIGHT = 6;
	private static final int PAD_BOTTOM_Y = HEIGHT/2 - PAD_HEIGHT/2;
	private static final int PAD_SECTION_SIZE = PAD_HEIGHT/3;
	private static final int PAD_BOTTOM_SECTION = PAD_SECTION_SIZE;
	private static final int PAD_MIDDLE_SECTION = 2*PAD_SECTION_SIZE;
	private static final int PAD_TOP_SECTION = 3*PAD_SECTION_SIZE;
	private static final int UPPER_PAD_BOUND = UPPER_BOUND - PAD_HEIGHT;
	private static final int LOWER_PAD_BOUND = 0;
	private static final int BALL_Y = HEIGHT/2;
	private static final int BEFORE_LEFT_PAD_X = 1;
	private static final int BEFORE_RIGHT_PAD_X = WIDTH - 2;
	
	private int leftPadBottomY = PAD_BOTTOM_Y;
	private int rightPadBottomY = PAD_BOTTOM_Y;
	private Point ballPos;
	
	private Board() {}
	
	public PadMovement moveLeftPad(PadMovement movement) {
		int newPadBottomY = leftPadBottomY + movement.getNextStep();
		if (newPadBottomY < LOWER_PAD_BOUND || newPadBottomY > UPPER_PAD_BOUND) {
			return PadMovement.STOP;
		}
		leftPadBottomY = newPadBottomY;
		return movement;
	}
	
	public PadMovement moveRightPad(PadMovement movement) {
		int newPadBottomY = rightPadBottomY + movement.getNextStep();
		if (newPadBottomY < LOWER_PAD_BOUND || newPadBottomY > UPPER_PAD_BOUND) {
			return PadMovement.STOP;
		}
		rightPadBottomY = newPadBottomY;
		return movement;
	}
	
	private Collision determinePadCollision(int distFromPadBottom) {
		if (distFromPadBottom >= 0 && distFromPadBottom < PAD_BOTTOM_SECTION) {
			return Collision.PAD_BOTTOM;
		} else if (distFromPadBottom >= PAD_BOTTOM_SECTION && distFromPadBottom < PAD_MIDDLE_SECTION) {
			return Collision.PAD_MIDDLE;
		} else if (distFromPadBottom >= PAD_MIDDLE_SECTION && distFromPadBottom < PAD_TOP_SECTION) {
			return Collision.PAD_TOP;
		}
		return Collision.END;
	}
	
	public Collision moveBall(Point to) {
		int xBallPos = to.getX();
		int yBallPos = to.getY();
		Collision collision = Collision.NONE;
		if (xBallPos <= BEFORE_LEFT_PAD_X) {
			int distFromPadBottom = leftPadBottomY - yBallPos;
			collision = determinePadCollision(distFromPadBottom);
		} else if (xBallPos >= BEFORE_RIGHT_PAD_X) {
			int distFromPadBottom = rightPadBottomY - yBallPos;
			collision = determinePadCollision(distFromPadBottom);
		} else if (yBallPos <= LOWER_BOUND || yBallPos >= UPPER_BOUND) {
			collision = Collision.SIDE;
		}
		// Ignore movement if out of bounds
		if (!(xBallPos < BEFORE_LEFT_PAD_X || xBallPos > BEFORE_RIGHT_PAD_X || yBallPos < LOWER_BOUND || yBallPos > UPPER_BOUND)) {
			ballPos = to;
		}
		return collision;
	}
	
	public static Board createDefaultBoard(HorizontalDirection startDirection) {
		Board board = new Board();
		int ballX = BEFORE_LEFT_PAD_X;
		if (startDirection == HorizontalDirection.LEFT) {
			ballX = BEFORE_RIGHT_PAD_X;
		}
		board.ballPos = new Point(ballX, BALL_Y);
		return board;
	}
	
	public Point getBallPos() {
		return ballPos;
	}

	public int getLeftPadBottomY() {
		return leftPadBottomY;
	}

	public int getRightPadBottomY() {
		return rightPadBottomY;
	}
	
}
